/**
 * echarts组件： 类目轴
 *
 * @desc echarts基于Canvas，纯Javascript图表库，提供直观，生动，可交互，可个性化定制的数据统计图表。
 * @author Kener (@Kener-林峰, kener.linfeng@gmail.com)
 *
 */


var Base = require('./base');
// 图形依赖
var TextShape = require('zrender/shape/Text');
var LineShape = require('zrender/shape/Line');
var RectangleShape = require('zrender/shape/Rectangle');
var ecConfig = require('../config');
// 类目轴
ecConfig.categoryAxis = {
    zlevel: 0,
    // 一级层叠
    z: 0,
    // 二级层叠
    show: true,
    position: 'bottom',
    // 位置
    name: '',
    // 坐标轴名字，默认为空
    nameLocation: 'end',
    // 坐标轴名字位置，支持'start' | 'end'
    nameTextStyle: {},
    // 坐标轴文字样式，默认取全局样式
    boundaryGap: true,
    // 类目起始和结束两端空白策略
    axisLine: {
        // 坐标轴线
        show: true,
        // 默认显示，属性show控制显示与否
        onZero: true,
        lineStyle: {
            // 属性lineStyle控制线条样式
            color: '#48b',
            width: 2,
            type: 'solid'
        }
    },
    axisTick: {
        // 坐标轴小标记
        show: true,
        // 属性show控制显示与否，默认不显示
        interval: 'auto',
        inside: false,
        // 控制小标记是否在grid里 
        // onGap: null,
        length: 5,
        // 属性length控制线长
        lineStyle: {
            // 属性lineStyle控制线条样式
            color: '#333',
            width: 1
        }
    },
    axisLabel: {
        // 坐标轴文本标签，详见axis.axisLabel
        show: true,
        interval: 'auto',
        rotate: 0,
        margin: 8,
        // clickable: false,
        // formatter: null,
        textStyle: {
            // 其余属性默认使用全局文本样式，详见TEXTSTYLE
            color: '#333'
        }
    },
    splitLine: {
        // 分隔线
        show: true,
        // 默认显示，属性show控制显示与否
        // onGap: null,
        lineStyle: {
            // 属性lineStyle（详见lineStyle）控制线条样式
            color: ['#ccc'],
            width: 1,
            type: 'solid'
        }
    },
    splitArea: {
        // 分隔区域
        show: false,
        // 默认不显示，属性show控制显示与否
        // onGap: null,
        areaStyle: {
            // 属性areaStyle（详见areaStyle）控制区域样式
            color: [
                'rgba(250,250,250,0.3)',
                'rgba(200,200,200,0.3)'
            ]
        }
    }
};
var zrUtil = require('zrender/tool/util');
var zrArea = require('zrender/tool/area');
/**
     * 构造函数
     * @param {Object} messageCenter echart消息中心
     * @param {ZRender} zr zrender实例
     * @param {Object} option 类目轴参数
     * @param {Grid} component 组件
     */
function CategoryAxis(ecTheme, messageCenter, zr, option, myChart, axisBase) {
    if (option.data.length < 1) {
        console.error('option.data.length < 1.');
        return;
    }
    Base.call(this, ecTheme, messageCenter, zr, option, myChart);
    this.grid = this.component.grid;
    for (var method in axisBase) {
        this[method] = axisBase[method];
    }
    this.refresh(option);
}
CategoryAxis.prototype = {
    type: ecConfig.COMPONENT_TYPE_AXIS_CATEGORY,
    _getReformedLabel: function (idx) {
        var data = this.getDataFromOption(this.option.data[idx]);
        var formatter = this.option.data[idx].formatter || this.option.axisLabel.formatter;
        if (formatter) {
            if (typeof formatter == 'function') {
                data = formatter.call(this.myChart, data);
            } else if (typeof formatter == 'string') {
                data = formatter.replace('{value}', data);
            }
        }
        return data;
    },
    /**
         * 计算标签显示挑选间隔
         */
    _getInterval: function () {
        var interval = this.option.axisLabel.interval;
        if (interval == 'auto') {
            // 麻烦的自适应计算
            var fontSize = this.option.axisLabel.textStyle.fontSize;
            var data = this.option.data;
            var dataLength = this.option.data.length;
            if (this.isHorizontal()) {
                // 横向
                if (dataLength > 3) {
                    var gap = this.getGap();
                    var isEnough = false;
                    var labelSpace;
                    var labelSize;
                    var step = Math.floor(0.5 / gap);
                    step = step < 1 ? 1 : step;
                    interval = Math.floor(15 / gap);
                    while (!isEnough && interval < dataLength) {
                        interval += step;
                        isEnough = true;
                        labelSpace = Math.floor(gap * interval);
                        // 标签左右至少间隔为3px
                        for (var i = Math.floor((dataLength - 1) / interval) * interval; i >= 0; i -= interval) {
                            if (this.option.axisLabel.rotate !== 0) {
                                // 有旋转
                                labelSize = fontSize;
                            } else if (data[i].textStyle) {
                                labelSize = zrArea.getTextWidth(this._getReformedLabel(i), this.getFont(zrUtil.merge(data[i].textStyle, this.option.axisLabel.textStyle)));
                            } else {
                                /*
                                    labelSize = zrArea.getTextWidth(
                                        this._getReformedLabel(i),
                                        font
                                    );
                                    */
                                // 不定义data级特殊文本样式，用fontSize优化getTextWidth
                                var label = this._getReformedLabel(i) + '';
                                var wLen = (label.match(/\w/g) || '').length;
                                var oLen = label.length - wLen;
                                labelSize = wLen * fontSize * 2 / 3 + oLen * fontSize;
                            }
                            if (labelSpace < labelSize) {
                                // 放不下，中断循环让interval++
                                isEnough = false;
                                break;
                            }
                        }
                    }
                } else {
                    // 少于3个则全部显示
                    interval = 1;
                }
            } else {
                // 纵向
                if (dataLength > 3) {
                    var gap = this.getGap();
                    interval = Math.floor(11 / gap);
                    // 标签上下至少间隔为3px
                    while (gap * interval - 6 < fontSize && interval < dataLength) {
                        interval++;
                    }
                } else {
                    // 少于3个则全部显示
                    interval = 1;
                }
            }
        } else {
            // 用户自定义间隔，支持funtion
            interval = typeof interval == 'function' ? 1 : interval - 0 + 1;
        }
        return interval;
    },
    /**
         * 绘制图形
         */
    _buildShape: function () {
        // 标签显示的挑选间隔
        this._interval = this._getInterval();
        if (!this.option.show) {
            return;
        }
        this.option.splitArea.show && this._buildSplitArea();
        this.option.splitLine.show && this._buildSplitLine();
        this.option.axisLine.show && this._buildAxisLine();
        this.option.axisTick.show && this._buildAxisTick();
        this.option.axisLabel.show && this._buildAxisLabel();
        for (var i = 0, l = this.shapeList.length; i < l; i++) {
            this.zr.addShape(this.shapeList[i]);
        }
    },
    // 小标记
    _buildAxisTick: function () {
        var axShape;
        var data = this.option.data;
        var dataLength = this.option.data.length;
        var tickOption = this.option.axisTick;
        var length = tickOption.length;
        var color = tickOption.lineStyle.color;
        var lineWidth = tickOption.lineStyle.width;
        var intervalFunction = typeof tickOption.interval == 'function' ? tickOption.interval : tickOption.interval == 'auto' ? typeof this.option.axisLabel.interval == 'function' ? this.option.axisLabel.interval : false : false;
        var interval = intervalFunction ? 1 : tickOption.interval == 'auto' ? this._interval : tickOption.interval - 0 + 1;
        var onGap = tickOption.onGap;
        var optGap = onGap ? this.getGap() / 2 : typeof onGap == 'undefined' ? this.option.boundaryGap ? this.getGap() / 2 : 0 : 0;
        var startIndex = optGap > 0 ? -interval : 0;
        if (this.isHorizontal()) {
            // 横向
            var yPosition = this.option.position == 'bottom' ? tickOption.inside ? this.grid.getYend() - length - 1 : this.grid.getYend() + 1 : tickOption.inside ? this.grid.getY() + 1 : this.grid.getY() - length - 1;
            var x;
            for (var i = startIndex; i < dataLength; i += interval) {
                if (intervalFunction && !intervalFunction(i, data[i])) {
                    // 回调并且回调返回false则跳过渲染
                    continue;
                }
                // 亚像素优化
                x = this.subPixelOptimize(this.getCoordByIndex(i) + (i >= 0 ? optGap : 0), lineWidth);
                axShape = {
                    _axisShape: 'axisTick',
                    zlevel: this.getZlevelBase(),
                    z: this.getZBase(),
                    hoverable: false,
                    style: {
                        xStart: x,
                        yStart: yPosition,
                        xEnd: x,
                        yEnd: yPosition + length,
                        strokeColor: color,
                        lineWidth: lineWidth
                    }
                };
                this.shapeList.push(new LineShape(axShape));
            }
        } else {
            // 纵向
            var xPosition = this.option.position == 'left' ? tickOption.inside ? this.grid.getX() + 1 : this.grid.getX() - length - 1 : tickOption.inside ? this.grid.getXend() - length - 1 : this.grid.getXend() + 1;
            var y;
            for (var i = startIndex; i < dataLength; i += interval) {
                if (intervalFunction && !intervalFunction(i, data[i])) {
                    // 回调并且回调返回false则中断渲染
                    continue;
                }
                // 亚像素优化
                y = this.subPixelOptimize(this.getCoordByIndex(i) - (i >= 0 ? optGap : 0), lineWidth);
                axShape = {
                    _axisShape: 'axisTick',
                    zlevel: this.getZlevelBase(),
                    z: this.getZBase(),
                    hoverable: false,
                    style: {
                        xStart: xPosition,
                        yStart: y,
                        xEnd: xPosition + length,
                        yEnd: y,
                        strokeColor: color,
                        lineWidth: lineWidth
                    }
                };
                this.shapeList.push(new LineShape(axShape));
            }
        }
    },
    // 坐标轴文本
    _buildAxisLabel: function () {
        var axShape;
        var data = this.option.data;
        var dataLength = this.option.data.length;
        var labelOption = this.option.axisLabel;
        var rotate = labelOption.rotate;
        var margin = labelOption.margin;
        var clickable = labelOption.clickable;
        var textStyle = labelOption.textStyle;
        var intervalFunction = typeof labelOption.interval == 'function' ? labelOption.interval : false;
        var dataTextStyle;
        if (this.isHorizontal()) {
            // 横向
            var yPosition;
            var baseLine;
            if (this.option.position == 'bottom') {
                yPosition = this.grid.getYend() + margin;
                baseLine = 'top';
            } else {
                yPosition = this.grid.getY() - margin;
                baseLine = 'bottom';
            }
            for (var i = 0; i < dataLength; i += this._interval) {
                if (intervalFunction && !intervalFunction(i, data[i]) || this._getReformedLabel(i) === ''    // 空文本优化
) {
                    continue;
                }
                dataTextStyle = zrUtil.merge(data[i].textStyle || {}, textStyle);
                axShape = {
                    // shape : 'text',
                    zlevel: this.getZlevelBase(),
                    z: this.getZBase() + 3,
                    hoverable: false,
                    style: {
                        x: this.getCoordByIndex(i),
                        y: yPosition,
                        color: dataTextStyle.color,
                        text: this._getReformedLabel(i),
                        textFont: this.getFont(dataTextStyle),
                        textAlign: dataTextStyle.align || 'center',
                        textBaseline: dataTextStyle.baseline || baseLine
                    }
                };
                if (rotate) {
                    axShape.style.textAlign = rotate > 0 ? this.option.position == 'bottom' ? 'right' : 'left' : this.option.position == 'bottom' ? 'left' : 'right';
                    axShape.rotation = [
                        rotate * Math.PI / 180,
                        axShape.style.x,
                        axShape.style.y
                    ];
                }
                this.shapeList.push(new TextShape(this._axisLabelClickable(clickable, axShape)));
            }
        } else {
            // 纵向
            var xPosition;
            var align;
            if (this.option.position == 'left') {
                xPosition = this.grid.getX() - margin;
                align = 'right';
            } else {
                xPosition = this.grid.getXend() + margin;
                align = 'left';
            }
            for (var i = 0; i < dataLength; i += this._interval) {
                if (intervalFunction && !intervalFunction(i, data[i]) || this._getReformedLabel(i) === ''    // 空文本优化
) {
                    continue;
                }
                dataTextStyle = zrUtil.merge(data[i].textStyle || {}, textStyle);
                axShape = {
                    // shape : 'text',
                    zlevel: this.getZlevelBase(),
                    z: this.getZBase() + 3,
                    hoverable: false,
                    style: {
                        x: xPosition,
                        y: this.getCoordByIndex(i),
                        color: dataTextStyle.color,
                        text: this._getReformedLabel(i),
                        textFont: this.getFont(dataTextStyle),
                        textAlign: dataTextStyle.align || align,
                        textBaseline: dataTextStyle.baseline || i === 0 && this.option.name !== '' ? 'bottom' : i == dataLength - 1 && this.option.name !== '' ? 'top' : 'middle'
                    }
                };
                if (rotate) {
                    axShape.rotation = [
                        rotate * Math.PI / 180,
                        axShape.style.x,
                        axShape.style.y
                    ];
                }
                this.shapeList.push(new TextShape(this._axisLabelClickable(clickable, axShape)));
            }
        }
    },
    _buildSplitLine: function () {
        var axShape;
        var data = this.option.data;
        var dataLength = this.option.data.length;
        var sLineOption = this.option.splitLine;
        var lineType = sLineOption.lineStyle.type;
        var lineWidth = sLineOption.lineStyle.width;
        var color = sLineOption.lineStyle.color;
        color = color instanceof Array ? color : [color];
        var colorLength = color.length;
        // splitLine随axisLable
        var intervalFunction = typeof this.option.axisLabel.interval == 'function' ? this.option.axisLabel.interval : false;
        var onGap = sLineOption.onGap;
        var optGap = onGap ? this.getGap() / 2 : typeof onGap == 'undefined' ? this.option.boundaryGap ? this.getGap() / 2 : 0 : 0;
        dataLength -= onGap || typeof onGap == 'undefined' && this.option.boundaryGap ? 1 : 0;
        if (this.isHorizontal()) {
            // 横向
            var sy = this.grid.getY();
            var ey = this.grid.getYend();
            var x;
            for (var i = 0; i < dataLength; i += this._interval) {
                if (intervalFunction && !intervalFunction(i, data[i])) {
                    // 回调并且回调返回false则跳过渲染
                    continue;
                }
                // 亚像素优化
                x = this.subPixelOptimize(this.getCoordByIndex(i) + optGap, lineWidth);
                axShape = {
                    // shape : 'line',
                    zlevel: this.getZlevelBase(),
                    z: this.getZBase(),
                    hoverable: false,
                    style: {
                        xStart: x,
                        yStart: sy,
                        xEnd: x,
                        yEnd: ey,
                        strokeColor: color[i / this._interval % colorLength],
                        lineType: lineType,
                        lineWidth: lineWidth
                    }
                };
                this.shapeList.push(new LineShape(axShape));
            }
        } else {
            // 纵向
            var sx = this.grid.getX();
            var ex = this.grid.getXend();
            var y;
            for (var i = 0; i < dataLength; i += this._interval) {
                if (intervalFunction && !intervalFunction(i, data[i])) {
                    // 回调并且回调返回false则跳过渲染
                    continue;
                }
                // 亚像素优化
                y = this.subPixelOptimize(this.getCoordByIndex(i) - optGap, lineWidth);
                axShape = {
                    // shape : 'line',
                    zlevel: this.getZlevelBase(),
                    z: this.getZBase(),
                    hoverable: false,
                    style: {
                        xStart: sx,
                        yStart: y,
                        xEnd: ex,
                        yEnd: y,
                        strokeColor: color[i / this._interval % colorLength],
                        lineType: lineType,
                        lineWidth: lineWidth
                    }
                };
                this.shapeList.push(new LineShape(axShape));
            }
        }
    },
    _buildSplitArea: function () {
        var axShape;
        var data = this.option.data;
        var sAreaOption = this.option.splitArea;
        var color = sAreaOption.areaStyle.color;
        if (!(color instanceof Array)) {
            // 非数组一律认为是单一颜色的字符串，单一颜色则用一个背景，颜色错误不负责啊！！！
            axShape = {
                // shape : 'rectangle',
                zlevel: this.getZlevelBase(),
                z: this.getZBase(),
                hoverable: false,
                style: {
                    x: this.grid.getX(),
                    y: this.grid.getY(),
                    width: this.grid.getWidth(),
                    height: this.grid.getHeight(),
                    color: color    // type : this.option.splitArea.areaStyle.type,
                }
            };
            this.shapeList.push(new RectangleShape(axShape));
        } else {
            // 多颜色
            var colorLength = color.length;
            var dataLength = this.option.data.length;
            // splitArea随axisLable
            var intervalFunction = typeof this.option.axisLabel.interval == 'function' ? this.option.axisLabel.interval : false;
            var onGap = sAreaOption.onGap;
            var optGap = onGap ? this.getGap() / 2 : typeof onGap == 'undefined' ? this.option.boundaryGap ? this.getGap() / 2 : 0 : 0;
            if (this.isHorizontal()) {
                // 横向
                var y = this.grid.getY();
                var height = this.grid.getHeight();
                var lastX = this.grid.getX();
                var curX;
                for (var i = 0; i <= dataLength; i += this._interval) {
                    if (intervalFunction && !intervalFunction(i, data[i]) && i < dataLength) {
                        // 回调并且回调返回false则跳过渲染
                        continue;
                    }
                    curX = i < dataLength ? this.getCoordByIndex(i) + optGap : this.grid.getXend();
                    axShape = {
                        // shape : 'rectangle',
                        zlevel: this.getZlevelBase(),
                        z: this.getZBase(),
                        hoverable: false,
                        style: {
                            x: lastX,
                            y: y,
                            width: curX - lastX,
                            height: height,
                            color: color[i / this._interval % colorLength]    // type : this.option.splitArea.areaStyle.type,
                        }
                    };
                    this.shapeList.push(new RectangleShape(axShape));
                    lastX = curX;
                }
            } else {
                // 纵向
                var x = this.grid.getX();
                var width = this.grid.getWidth();
                var lastYend = this.grid.getYend();
                var curY;
                for (var i = 0; i <= dataLength; i += this._interval) {
                    if (intervalFunction && !intervalFunction(i, data[i]) && i < dataLength) {
                        // 回调并且回调返回false则跳过渲染
                        continue;
                    }
                    curY = i < dataLength ? this.getCoordByIndex(i) - optGap : this.grid.getY();
                    axShape = {
                        // shape : 'rectangle',
                        zlevel: this.getZlevelBase(),
                        z: this.getZBase(),
                        hoverable: false,
                        style: {
                            x: x,
                            y: curY,
                            width: width,
                            height: lastYend - curY,
                            color: color[i / this._interval % colorLength]    // type : this.option.splitArea.areaStyle.type
                        }
                    };
                    this.shapeList.push(new RectangleShape(axShape));
                    lastYend = curY;
                }
            }
        }
    },
    /**
         * 刷新
         */
    refresh: function (newOption) {
        if (newOption) {
            this.option = this.reformOption(newOption);
            // 通用字体设置
            this.option.axisLabel.textStyle = this.getTextStyle(this.option.axisLabel.textStyle);
        }
        this.clear();
        this._buildShape();
    },
    /**
         * 返回间隔
         */
    getGap: function () {
        var dataLength = this.option.data.length;
        var total = this.isHorizontal() ? this.grid.getWidth() : this.grid.getHeight();
        if (this.option.boundaryGap) {
            // 留空
            return total / dataLength;
        } else {
            // 顶头
            return total / (dataLength > 1 ? dataLength - 1 : 1);
        }
    },
    // 根据值换算位置
    getCoord: function (value) {
        var data = this.option.data;
        var dataLength = data.length;
        var gap = this.getGap();
        var position = this.option.boundaryGap ? gap / 2 : 0;
        for (var i = 0; i < dataLength; i++) {
            if (this.getDataFromOption(data[i]) == value) {
                if (this.isHorizontal()) {
                    // 横向
                    position = this.grid.getX() + position;
                } else {
                    // 纵向
                    position = this.grid.getYend() - position;
                }
                return position;    // Math.floor可能引起一些偏差，但性能会更好
                                    /* 准确更重要
                    return (i === 0 || i == dataLength - 1)
                           ? position
                           : Math.floor(position);
                    */
            }
            position += gap;
        }
    },
    // 根据类目轴数据索引换算位置
    getCoordByIndex: function (dataIndex) {
        if (dataIndex < 0) {
            if (this.isHorizontal()) {
                return this.grid.getX();
            } else {
                return this.grid.getYend();
            }
        } else if (dataIndex > this.option.data.length - 1) {
            if (this.isHorizontal()) {
                return this.grid.getXend();
            } else {
                return this.grid.getY();
            }
        } else {
            var gap = this.getGap();
            var position = this.option.boundaryGap ? gap / 2 : 0;
            position += dataIndex * gap;
            if (this.isHorizontal()) {
                // 横向
                position = this.grid.getX() + position;
            } else {
                // 纵向
                position = this.grid.getYend() - position;
            }
            return position;    /* 准确更重要
                return (dataIndex === 0 || dataIndex == this.option.data.length - 1)
                       ? position
                       : Math.floor(position);
                */
        }
    },
    // 根据类目轴数据索引换算类目轴名称
    getNameByIndex: function (dataIndex) {
        return this.getDataFromOption(this.option.data[dataIndex]);
    },
    // 根据类目轴名称换算类目轴数据索引
    getIndexByName: function (name) {
        var data = this.option.data;
        var dataLength = data.length;
        for (var i = 0; i < dataLength; i++) {
            if (this.getDataFromOption(data[i]) == name) {
                return i;
            }
        }
        return -1;
    },
    // 根据位置换算值
    getValueFromCoord: function () {
        return '';
    },
    /**
         * 根据类目轴数据索引返回是否为主轴线
         * @param {number} dataIndex 类目轴数据索引
         * @return {boolean} 是否为主轴
         */
    isMainAxis: function (dataIndex) {
        return dataIndex % this._interval === 0;
    }
};
zrUtil.inherits(CategoryAxis, Base);
require('../component').define('categoryAxis', CategoryAxis);
module.exports = CategoryAxis || module.exports;;